package ru.common.hibernate;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.transaction.annotation.Transactional;

public class HibernateActionExecutorImpl implements HibernateActionExecutor {

    private static Log LOGGER = LogFactory.getLog(HibernateActionExecutorImpl.class);

    private final ExecutorService executor;

    private final HibernateTemplate hibernateTemplate;

    /** AOP */
    protected HibernateActionExecutorImpl() {
        this(null, null);
    }

    public HibernateActionExecutorImpl(final HibernateTemplate hibernateTemplate,
            ExecutorService executor) {
        this.hibernateTemplate = hibernateTemplate;
        this.executor = executor;
    }

    @Override
    @Transactional
    public <T> T execute(final HibernateAction<T> action) {
        try {
            final ActionCallback<T> callback = new ActionCallback<T>(action);
            hibernateTemplate.execute(callback);
            return callback.getResult();
        } catch (final RuntimeException e) {
            LOGGER.error("Hibernate action execution", e);
            throw e;
        }
    }

    public <T> T executeSeparately(final HibernateAction<T> action) {
        try {
            return executor.submit(new Callable<T>() {

                @Override
                public T call() throws Exception {
                    return execute(action);
                }

            }).get();
        } catch (final InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException(e);
        } catch (final ExecutionException e) {
            throw new IllegalStateException(e);
        }
    }

}
